package com.ruoyi.web.schedule;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.web.constant.RedisKeyPrefixConstant;
import com.ruoyi.web.constant.WalletConstant;
import com.ruoyi.web.domain.Currency;
import com.ruoyi.web.domain.RechargeRecord;
import com.ruoyi.web.enums.CommonDictEnum;
import com.ruoyi.web.enums.RechargeRecordEnum;
import com.ruoyi.web.enums.UserEnums;
import com.ruoyi.web.runner.SendServiceCharge;
import com.ruoyi.web.service.IAppUserService;
import com.ruoyi.web.service.ICurrencyService;
import com.ruoyi.web.service.IRechargeRecordService;
import com.ruoyi.web.service.IUserCapitalService;
import com.ruoyi.web.utils.MysqlUtil;
import lombok.AllArgsConstructor;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.methods.response.EthBlockNumber;
import org.web3j.protocol.http.HttpService;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Set;

/**
 * 充值记录校验
 *
 */
@Component
@EnableScheduling
@AllArgsConstructor
public class RechargeRecordCheckTask {

	public final RedisCache redis;

	private final IRechargeRecordService recordService;

	private final IUserCapitalService accountService;

	private final SendServiceCharge serviceCharge;

	private final ICurrencyService currencyService;
	private final IAppUserService appUserService;
	private final MysqlUtil mysqlUtil;

	private final OkHttpClient okHttpClient = new OkHttpClient();

	@Scheduled(fixedDelay = 2000)
	public void recordCheckTask() {
		try {
			Set<String> keys = redis.getHashKeys(RedisKeyPrefixConstant.RECHARGE_RECORD_CHECK);
			for (String key : keys) {
				try {
					Integer o = (Integer) redis.getCacheMapValue(RedisKeyPrefixConstant.RECHARGE_RECORD_CHECK, key);
					if (o == null) {
						break;
					}
					// 充值记录
					RechargeRecord rechargeRecord = recordService.selectRechargeRecordById(Long.valueOf(key));
					String newestBlockNumber;
					// UNT
					if (UserEnums.Chain.ETH.getValue().equals(rechargeRecord.getPublicChain())) {
						List<Currency> currencies = currencyService.selectCurrencyList(new Currency() {{
							setName(WalletConstant.USDT);
							setPublicChain(UserEnums.Chain.ETH.getValue());
							setState(CommonDictEnum.Status.NORMAL.getValue());
						}});
						Currency currency = currencies.size() > 0 ? currencies.get(0) : null;
						if (currency == null) {
							break;
						}
						Web3j web3j = Web3j.build(new HttpService(currency.getNodeAddress() + currency.getApiKey()));
						Request<?, EthBlockNumber> ethBlockNumberRequest = web3j.ethBlockNumber();
						EthBlockNumber send = ethBlockNumberRequest.send();
						newestBlockNumber = String.valueOf(send.getBlockNumber());
					}
					// 币安
					else if (UserEnums.Chain.BSC.getValue().equals(rechargeRecord.getPublicChain())) {
						List<Currency> currencies = currencyService.selectCurrencyList(new Currency() {{
							setName(WalletConstant.USDT);
							setPublicChain(UserEnums.Chain.BSC.getValue());
							setState(CommonDictEnum.Status.NORMAL.getValue());
						}});
						Currency currency = currencies.size() > 0 ? currencies.get(0) : null;
						if (currency == null) {
							break;
						}
						Web3j web3j = Web3j.build(new HttpService(currency.getNodeAddress()));
						Request<?, EthBlockNumber> ethBlockNumberRequest = web3j.ethBlockNumber();
						EthBlockNumber send = ethBlockNumberRequest.send();
						newestBlockNumber = String.valueOf(send.getBlockNumber());
					}
					// 波场
					else if (UserEnums.Chain.TRX.getValue().equals(rechargeRecord.getPublicChain())) {
						List<Currency> currencies = currencyService.selectCurrencyList(new Currency() {{
							setName(WalletConstant.USDT);
							setPublicChain(UserEnums.Chain.TRX.getValue());
							setState(CommonDictEnum.Status.NORMAL.getValue());
						}});
						Currency currency = currencies.size() > 0 ? currencies.get(0) : null;
						if (currency == null) {
							break;
						}

						okhttp3.Request request = new okhttp3.Request.Builder()
								.url(currency.getNodeAddress() + "walletsolidity/getnowblock")
								.get()
								.addHeader("Accept", "application/json")
								.build();

						Response response = null;
						try {
							response = okHttpClient.newCall(request).execute();
						} catch (IOException e) {
							throw new RuntimeException(e);
						}
						String res = null;
						try {
							res = response.body().string();
						} catch (IOException e) {
							throw new RuntimeException(e);
						}
						newestBlockNumber = JSONUtil.parseObj(res).getJSONObject("block_header").getJSONObject("raw_data").getStr("number");
					} else {
						break;
					}
					// 区块确认数未达到不做处理
					String blockNumber = rechargeRecord.getBlockNumber();
					BigDecimal sub = NumberUtil.sub(String.valueOf(newestBlockNumber), blockNumber);
					int compare = NumberUtil.compare(NumberUtil.parseLong(String.valueOf(sub)), NumberUtil.parseLong(rechargeRecord.getBlockConfirmationRechargeNumber()));
					if (compare < 0) {
						break;
					}
					rechargeRecord.setBlockConfirmationNumber(String.valueOf(sub));
					// 最小充值数
					int rechargeCompare = rechargeRecord.getQuantity().compareTo(rechargeRecord.getMinimumRechargeNumber());
					if (rechargeCompare < 0) {
						// 未达到最小充值数量 充值失败
						rechargeRecord.setState(RechargeRecordEnum.Status.FAIL.getValue());
						rechargeRecord.setRemark("未达到最小充值数量 无法入账");
						recordService.updateRechargeRecord(rechargeRecord);
						redis.deleteCacheMapValue(RedisKeyPrefixConstant.RECHARGE_RECORD_CHECK, key);
						break;
					}
					// 充值成功
					rechargeRecord.setState(RechargeRecordEnum.Status.SUCCESS.getValue());
					mysqlUtil.startLocalTx();
					// 更新用户的资金账户余额
					recordService.updateRechargeRecord(rechargeRecord);
					// 修改资金账户余额
					accountService.rechargeThen(rechargeRecord);
					// 查询上级,充值分红
					appUserService.rechargeDistribution(rechargeRecord);
					// 给用户预存归集所需的手续费
					if (UserEnums.Chain.ETH.getValue().equals(rechargeRecord.getPublicChain())) {
						serviceCharge.ethFee(rechargeRecord,UserEnums.Chain.ETH.getValue());
					}
					if (UserEnums.Chain.BSC.getValue().equals(rechargeRecord.getPublicChain())) {
						serviceCharge.ethFee(rechargeRecord,UserEnums.Chain.BSC.getValue());
					}
					if (UserEnums.Chain.TRX.getValue().equals(rechargeRecord.getPublicChain())) {
						serviceCharge.tronFee(rechargeRecord);
					}
					// 删除redis缓存 新增发送邮件缓存
					redis.deleteCacheMapValue(RedisKeyPrefixConstant.RECHARGE_RECORD_CHECK, key);
					mysqlUtil.commitLocalTx();
				} catch (Exception e) {
					mysqlUtil.rollbackLocalTx();
					e.printStackTrace();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
